﻿using Glorysoft.Auto.Xfw;
using Serilog.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Cache;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Glorysoft.EAP.Contracts.Odyssey
{
    /// <summary>
    /// SOAP辅助类
    /// </summary>
    public static class SoapHelper
    {
      
        /// <summary>
        /// 消息体格式
        /// </summary>
        private const String FORMAT_ENVELOPE = @"<?xml version='1.0' encoding='utf-8'?>
                <soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
                  <soap:Body>
                    <{0} xmlns='{1}'>{2}</{0}>
                  </soap:Body>
                </soap:Envelope>";
        /// <summary>
        /// 参数格式
        /// </summary>
        private const String FORMAT_PARAMETER = "<{0}>{1}</{0}>";

        /// <summary>
        /// 序列化
        /// </summary>
        /// <param name="soapAction">SOAP动作</param>
        /// <param name="soapParameters">参数集合</param>
        /// <returns>返回值</returns>
        public static String MakeEnvelope(String soapAction, params SoapParameter[] soapParameters)
        {
            String nameSpace, methodName;

            GetNameSpaceAndMethodName(soapAction, out nameSpace, out methodName);

            return String.Format(FORMAT_ENVELOPE, methodName, nameSpace, BuildSoapParameters(soapParameters));
        }

        /// <summary>
        /// 创建SOAP参数内容
        /// </summary>
        /// <param name="soapParameters">参数集合</param>
        /// <returns>SOAP参数内容</returns>
        public static String BuildSoapParameters(IEnumerable<SoapParameter> soapParameters)
        {
            var buffer = new StringBuilder();

            foreach (var soapParameter in soapParameters)
            {
                var strContent = GetObjectContent(soapParameter.Value);
                buffer.AppendFormat(FORMAT_PARAMETER, soapParameter.Name, strContent);
            }
            return buffer.ToString();
        }

        /// <summary>
        /// 获取名称空间
        /// </summary>
        /// <param name="soapAction">SOAP动作</param>
        /// <returns>名称空间</returns>
        public static String GetNameSpace(String soapAction)
        {
            String nameSpace, methodName;

            GetNameSpaceAndMethodName(soapAction, out nameSpace, out methodName);

            return nameSpace;
        }

        /// <summary>
        /// 获取函数名称
        /// </summary>
        /// <param name="soapAction">SOAP动作</param>
        /// <returns>函数名称</returns>
        public static String GetMethodName(String soapAction)
        {
            String nameSpace, methodName;

            GetNameSpaceAndMethodName(soapAction, out nameSpace, out methodName);

            return methodName;
        }

        /// <summary>
        /// 获取名称空间和函数名称
        /// </summary>
        /// <param name="soapAction">SOAP动作</param>
        /// <param name="nameSpace">名称空间</param>
        /// <param name="methodName">函数名称</param>
        public static void GetNameSpaceAndMethodName(String soapAction, out String nameSpace, out String methodName)
        {
            nameSpace = (methodName = String.Empty);

            var index = soapAction.LastIndexOf(Path.AltDirectorySeparatorChar);
            nameSpace = soapAction.Substring(0, index + 1);
            methodName = soapAction.Substring(index + 1, soapAction.Length - index - 1);
        }

        /// <summary>
        /// 获取对象内容XML
        /// </summary>
        /// <param name="graph">图</param>
        /// <returns>对象内容XML</returns>
        public static String GetObjectContent(Object graph)
        {
            using (var memoryStream = new MemoryStream())
            {
                var graphType = graph.GetType();
                var xmlSerializer = new XmlSerializer(graphType);

                // XML序列化
                xmlSerializer.Serialize(memoryStream, graph);

                // 获取对象XML
                var strContent = Encoding.UTF8.GetString(memoryStream.ToArray());
                var xmlDocument = new XmlDocument();

                xmlDocument.LoadXml(strContent);

                // 返回对象内容XML
                var contentNode = xmlDocument.SelectSingleNode(graphType.Name);

                if (contentNode != null)
                    return contentNode.InnerXml;

                return graph.ToString();
            }
        }
    }

    /// <summary>
    /// SOAP参数
    /// </summary>
    public sealed class SoapParameter
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="value">值</param>
        public SoapParameter(String name, Object value)
        {
            this.Name = name;
            this.Value = value;
        }

        /// <summary>
        /// 名称
        /// </summary>
        public String Name { get; private set; }

        /// <summary>
        /// 值
        /// </summary>
        public Object Value { get; private set; }
    }

    /// <summary>
    /// SOAP客户端
    /// </summary>
    public sealed class SoapClient
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="uriString">请求地址</param>
        /// <param name="soapAction">SOAP动作</param>
        public SoapClient(String uriString, String soapAction)
            : this(new Uri(uriString), soapAction) { }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="uri">请求地址</param>
        /// <param name="soapAction">SOAP动作</param>
        public SoapClient(Uri uri, String soapAction)
        {
            this.Uri = uri;
            this.SoapAction = soapAction;
            this.Credentials = CredentialCache.DefaultNetworkCredentials;
        }
        public SoapClient(string uri)
        {
            this.Uri = new Uri(uri);
            this.Credentials = CredentialCache.DefaultNetworkCredentials;
        }

        /// <summary>
        /// 身份凭证
        /// </summary>
        public ICredentials Credentials { get; set; }

        /// <summary>
        /// 请求地址
        /// </summary>
        public Uri Uri { get; set; }

        /// <summary>
        /// SOAP动作
        /// </summary>
        public string SoapAction { get; set; }

        /// <summary>
        /// 获取响应
        /// </summary>
        /// <returns>响应</returns>
        public string HttpRequest(string fucName, string body)
        {
            try
            {
                Logger CimLogger = XfwContext.LogManager.DbLogger;
                var request = MakeEnvelope(fucName, body);
                var webRequest = (HttpWebRequest)WebRequest.Create(this.Uri);
                webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
                webRequest.ContentType = "text/xml;charset=UTF-8";
                webRequest.Headers.Add("SOAPAction", SoapAction);
                webRequest.KeepAlive = true;
                webRequest.Method = "POST";
               
                byte[] data = Encoding.UTF8.GetBytes(request);
                 webRequest.ContentLength = data.Length;
                Stream newStream = webRequest.GetRequestStream();
                newStream.Write(data, 0, data.Length);

                string reqq = string.Empty;
                foreach (char item in request)
                {
                    reqq += item.ToString();
                    if (item == ',')
                    {
                        reqq += "\r\n";
                    }
                    if (item == '{')
                    {
                        reqq += "\r\n";
                    }
                }
                CimLogger.Information($" EAP<MES.Execute. Text:\r\n{reqq}");

                HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
                using (Stream resStream = response.GetResponseStream())
                {
                    var xmlReader = XmlTextReader.Create(resStream);
                    var xmlDocument = new XmlDocument();

                    // 加载响应XML
                    xmlDocument.Load(xmlReader);

                    var nsmgr = new XmlNamespaceManager(xmlDocument.NameTable);
                    nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

                    var bodyNode = xmlDocument.SelectSingleNode("soap:Envelope/soap:Body", nsmgr);

                    if (bodyNode.FirstChild.HasChildNodes)
                        return bodyNode.FirstChild.FirstChild.InnerXml;
                }
                return null;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        /// <summary>
        /// 获取响应
        /// </summary>
        /// <returns>响应</returns>
        public string HttpRequestList(string fucName, Dictionary<string, string> paramss)
        {
            try
            {
                Logger CimLogger = XfwContext.LogManager.DbLogger;
                var request = MakeEnvelopes(fucName, paramss);
                var webRequest = (HttpWebRequest)WebRequest.Create(this.Uri);
                webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
                webRequest.ContentType = "text/xml;charset=UTF-8";
                webRequest.Headers.Add("SOAPAction", SoapAction);
                webRequest.KeepAlive = true;
                webRequest.Method = "POST";

                byte[] data = Encoding.UTF8.GetBytes(request);
                webRequest.ContentLength = data.Length;
                Stream newStream = webRequest.GetRequestStream();
                newStream.Write(data, 0, data.Length);

                string reqq = request.Replace(",", ",\r\n").Replace("{", "{ \r\n");
                //foreach (char item in request)
                //{
                //    reqq += item.ToString();
                //    if (item == ',')
                //    {
                //        reqq += "\r\n";
                //    }
                //    if (item == '{')
                //    {
                //        reqq += "\r\n";
                //    }
                //}
                CimLogger.Information($" EAP<MES.Execute. Text:\r\n{reqq}");

                HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
                using (Stream resStream = response.GetResponseStream())
                {
                    var xmlReader = XmlTextReader.Create(resStream);
                    var xmlDocument = new XmlDocument();

                    // 加载响应XML
                    xmlDocument.Load(xmlReader);

                    var nsmgr = new XmlNamespaceManager(xmlDocument.NameTable);
                    nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

                    var bodyNode = xmlDocument.SelectSingleNode("soap:Envelope/soap:Body", nsmgr);

                    if (bodyNode.FirstChild.HasChildNodes)
                        return bodyNode.FirstChild.FirstChild.InnerXml;
                }
                return null;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        public  string MakeEnvelope(string functionname, string jsonbody)
        {
            XNamespace soapenv = "http://schemas.xmlsoap.org/soap/envelope/";
            //var document = new XDocument(
            //               new XDeclaration("1.0", "utf-8", String.Empty),
            //               new XElement(soapenv + "Envelope",
            //                   new XAttribute(XNamespace.Xmlns + "soapenv", soapenv),
            //                   new XElement(soapenv + "Header"),
            //                   new XElement(soapenv + "Body",
            //                       new XElement(soapenv + functionname,
            //                       new XElement("json", jsonbody)
            //                       )
            //                   )
            //                ));
            var document = new XDocument(
                          new XDeclaration("1.0", "utf-8", String.Empty),
                          new XElement(soapenv + "Envelope",
                              new XAttribute(XNamespace.Xmlns + "soapenv", soapenv),
                              new XElement(soapenv + "Header"),
                              new XElement(soapenv + "Body",
                                  new XElement(soapenv + functionname,
                                  new XElement("requestMessage", jsonbody)
                                  )
                              )
                           ));
            return document.ToString();
        }
        public string MakeEnvelopes(string functionname, Dictionary<string, string> paramss)
        {
            //string apiname = functionname;
            //Dictionary<string, string> paramss = new Dictionary<string, string>() { { jsons.spl, "TEST" }, { "password", "123" }, { "facilityId", "DEMO" } };
            string paralist = "";
            foreach (var item in paramss)
            {
                paralist += $"<{item.Key} xsi:type=\"xsd:string\" xs:type=\"type:string\" xmlns:xs=\"http://www.w3.org/2000/XMLSchema-instance\">{item.Value}</{item.Key}>";
            }
            string soapstr = $"<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsdd=\"http://xml.fa-software.com/mycim/wsdd/\">"+
               " <soapenv:Header/>"+
                    "<soapenv:Body>"+
                        $"<wsdd:{functionname} soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"+
                        $"{paralist}"+
                        $"</wsdd:{functionname}>"+
                    "</soapenv:Body>"+
                "</soapenv:Envelope>";

            return soapstr;

            
        }
    }
}
